package org.hcyspartnoc.luoxin.service.system.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.hcyspartnoc.luoxin.common.core.PageBean;
import org.hcyspartnoc.luoxin.common.core.configuration.UserConfiguration;
import org.hcyspartnoc.luoxin.common.core.configuration.UtilsConfiguration;
import org.hcyspartnoc.luoxin.common.core.context.BaseContextHolder;
import org.hcyspartnoc.luoxin.common.core.enums.CoreSysRole;
import org.hcyspartnoc.luoxin.common.enums.system.SysUserStatusEnum;
import org.hcyspartnoc.luoxin.common.enums.user.UserContactTypeEnum;
import org.hcyspartnoc.luoxin.common.exception.common.CommonUtilsException;
import org.hcyspartnoc.luoxin.common.exception.framework.AuthException;
import org.hcyspartnoc.luoxin.common.exception.system.SysRoleException;
import org.hcyspartnoc.luoxin.common.exception.system.SysUserException;
import org.hcyspartnoc.luoxin.mapper.asset.AssetVirtualCounselorMapper;
import org.hcyspartnoc.luoxin.mapper.chat.ChatSessionMapper;
import org.hcyspartnoc.luoxin.mapper.chat.ChatSessionUserMapper;
import org.hcyspartnoc.luoxin.mapper.system.SysRoleMapper;
import org.hcyspartnoc.luoxin.mapper.system.SysRoleUserMapper;
import org.hcyspartnoc.luoxin.mapper.system.SysUserMapper;
import org.hcyspartnoc.luoxin.mapper.user.UserContactMapper;
import org.hcyspartnoc.luoxin.pojo.dto.system.*;
import org.hcyspartnoc.luoxin.pojo.po.asset.AssetVirtualCounselorPo;
import org.hcyspartnoc.luoxin.pojo.po.chat.ChatSessionUserPo;
import org.hcyspartnoc.luoxin.pojo.po.system.SysRolePo;
import org.hcyspartnoc.luoxin.pojo.po.system.SysRoleUserPo;
import org.hcyspartnoc.luoxin.pojo.po.system.SysUserPo;
import org.hcyspartnoc.luoxin.pojo.po.user.UserContactPo;
import org.hcyspartnoc.luoxin.pojo.vo.system.SysUserAdminVo;
import org.hcyspartnoc.luoxin.pojo.vo.system.SysUserVo;
import org.hcyspartnoc.luoxin.service.system.ISysUserService;
import org.hcyspartnoc.luoxin.service.user.impl.UserContactServiceImpl;
import org.hcyspartnoc.luoxin.utils.AliyunOssUtils;
import org.hcyspartnoc.luoxin.utils.StringUtils;
import org.hcyspartnoc.luoxin.utils.WeiXinUtils;
import org.hcyspartnoc.luoxin.utils.redis.RedisComponent;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserPo> implements ISysUserService {
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private UserConfiguration userConfiguration;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private AliyunOssUtils aliyunOssUtils;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysRoleUserMapper sysRoleUserMapper;
    @Resource
    private UserContactMapper userContactMapper;
    @Resource
    private AssetVirtualCounselorMapper assetVirtualCounselorMapper;
    @Resource
    private ChatSessionMapper chatSessionMapper;
    @Resource
    private ChatSessionUserMapper chatSessionUserMapper;
    @Resource
    private UserContactServiceImpl userContactServiceImpl;
    @Resource
    private UtilsConfiguration utilsConfiguration;


//    @Override
//    @Transactional
//    public String registerByPhone(SysUserPhoneRegisterDto sysUserPhoneRegisterDto) throws SysUserException{
//        // 1. 检查手机号是否已经注册
//        String phoneNumber = sysUserPhoneRegisterDto.getPhone();
//        SysUser existingUser = sysUserMapper.selectUserByPhoneNumber(phoneNumber);
//        if (existingUser != null) {
//            throw new SysUserException(SysUserException.PHONE_HAS_EXISTS);
//        }
//        // 2. 创建新用户
//        SysUser newUser = new SysUser();
//        newUser.setPhoneNumber(phoneNumber);
//        newUser.setUsername(sysUserPhoneRegisterDto.getUsername());
//        newUser.setPassword(passwordEncoder.encode(sysUserPhoneRegisterDto.getPassword()));  // 加密密码
//        newUser.setCreateTime(LocalDateTime.now());
//        newUser.setStatus("ACTIVE"); // 根据你的业务逻辑设置用户状态
//        // 3. 保存新用户到数据库
//        int insertResult = sysUserMapper.insertUser(newUser);
//        if (insertResult != 1) {
//            throw new SysUserException("用户注册失败，请稍后再试");
//        }
//        // 4. 生成 JWT 或其他类型的 Token
//        String token = tokenService.generateToken(newUser);
//        // 5. 返回 Token
//        return token;
//    }

    @Override
    @Transactional
    public String registerByWx(SysUserWxRegisterDto sysUserWxRegisterDto) throws SysUserException {
        String sessionKeyOrOpenId = WeiXinUtils.getSessionKeyOrOpenId(sysUserWxRegisterDto.getJsCode());
        if (sessionKeyOrOpenId == null)// 抛出异常
            throw new SysUserException(SysUserException.JS_CODE_NOT_RIGHT);
        // 查询数据表是否存在当前用户，存在直接查询，不存在则创建用户
        SysUserPo savedUserPo = sysUserMapper.selectOne(new LambdaQueryWrapper<>(SysUserPo.class).eq(SysUserPo::getOpenId, sessionKeyOrOpenId));
        Integer uid;
        if (savedUserPo == null) {
            // 注册用户
            SysUserPo sysUserPo = new SysUserPo();
            Collections.shuffle(userConfiguration.getDefaultAvatar());
            sysUserPo.setAvatar(userConfiguration.getDefaultAvatar().get(0));
            sysUserPo.setOpenId(sessionKeyOrOpenId);
            sysUserPo.setNickname("用户_" + StringUtils.randomStr(10));
            String md5Pwd = StringUtils.encodeByMd5(StringUtils.randomStr(16), userConfiguration.getPwdSalt());
            sysUserPo.setPassword(md5Pwd);
            // 插入用户
            sysUserMapper.insert(sysUserPo);
            uid = sysUserPo.getId();
            // 将用户角色绑定为普通用户
            SysRoleUserPo sysRoleUserPo = new SysRoleUserPo();
            sysRoleUserPo.setUserId(uid);
            sysRoleUserPo.setRoleId(CoreSysRole.NORMAL_USER.getId());
            sysRoleUserMapper.insert(sysRoleUserPo);
            // 将用户关系加载到redis
            redisComponent.setRU_Relation(uid, sysRoleUserPo.getRoleId());
            // 将开放的模型添加为用户联系人
            List<AssetVirtualCounselorPo> assetVirtualCounselorPos = assetVirtualCounselorMapper.selectList(new LambdaQueryWrapper<>(AssetVirtualCounselorPo.class)
                    .eq(AssetVirtualCounselorPo::getIsOpen, true));
            UserContactPo userContactPo = new UserContactPo();
            userContactPo.setContactType(UserContactTypeEnum.V_COUNSELOR.getCode());
            userContactPo.setUserId(uid);
            for (AssetVirtualCounselorPo assetVirtualCounselorPo : assetVirtualCounselorPos) {
                userContactPo.setId(null);
                userContactPo.setContactRemark(assetVirtualCounselorPo.getName());
                userContactPo.setContactId(assetVirtualCounselorPo.getId());
                Db.save(userContactPo);
                userContactServiceImpl.createVCSession(assetVirtualCounselorPo, userContactPo, uid);
            }
        } else {
            if (savedUserPo.getStatus().equals(SysUserStatusEnum.DISABLE.getCode()))
                throw new SysUserException(SysUserException.USER_STATUS_ERROR);
            uid = savedUserPo.getId();
        }
        // 刷新最后登录时间
        reFleshLastLoginTime(uid);
        // 生成token将用户id和数据token建立关系
        return generateToken(uid);
    }

    @Override
    public String loginByPhone(SysUserLoginByPhoneDto sysUserLoginByPhoneDto) throws SysUserException, CommonUtilsException {
        // 校验验证码
        //使用redis校验
        if (!redisComponent.verifyImageCaptcha(sysUserLoginByPhoneDto.getCaptchaKey(), sysUserLoginByPhoneDto.getCaptcha()))
            throw new CommonUtilsException(CommonUtilsException.CAPTCHA_NOT_RIGHT);
        // 获取用户
        SysUserPo sysUserPo = sysUserMapper.selectOne(new LambdaQueryWrapper<>(SysUserPo.class)
                .eq(SysUserPo::getPhone, sysUserLoginByPhoneDto.getPhone()));
        // 用户不存在
        if (Objects.isNull(sysUserPo))
            throw new SysUserException(SysUserException.USER_NOT_EXISTS);
        // 用户状态异常
        if (sysUserPo.getStatus().equals(SysUserStatusEnum.DISABLE.getCode()))
            throw new SysUserException(SysUserException.USER_STATUS_ERROR);
        // 验证密码
        String encodePwd = StringUtils.encodeByMd5(sysUserLoginByPhoneDto.getPassword(), userConfiguration.getPwdSalt());
        if (!sysUserPo.getPassword().equals(encodePwd))
            throw new SysUserException(SysUserException.PASSWORD_NOT_RIGHT);
        // 销毁验证码
        redisComponent.removeImageCaptcha(sysUserLoginByPhoneDto.getCaptchaKey());
        // 刷新最后登录时间
        reFleshLastLoginTime(sysUserPo.getId());
        // 生成token将用户id和数据token建立关系
        return generateToken(sysUserPo.getId());
    }

    @Override
    @Transactional
    public void logout() throws SysUserException {
        SysUserPo currentUser = BaseContextHolder.getContext().getBaseCurrentUser();
        if (currentUser.getRoleId().equals(CoreSysRole.SUPER_ADMIN.getId()))
            throw new SysUserException(SysUserException.SUPER_ADMIN_COULD_NOT_LOGOUT);
        this.removeById(currentUser.getId());
    }

    @Override
    @Transactional
    public String modifyAvatar(MultipartFile image) throws CommonUtilsException, SysUserException {
        // 验证图像文件合法性 TODO
        String originalFilename = null;
        //获取原始的文件名
        if (Objects.isNull(originalFilename = image.getOriginalFilename()))
            throw new CommonUtilsException(CommonUtilsException.SRC_NOT_RIGHT);
        //在oss中存储名字就是UUID + 文件的后缀名
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        if (!utilsConfiguration.getFile().getAllowedImageTypes().contains(fileExtension.toUpperCase()))
            throw new CommonUtilsException(CommonUtilsException.SRC_NOT_RIGHT);
        String objectName = UUID.randomUUID() + "." + fileExtension;
        try {
            String resultURL = aliyunOssUtils.upload(image.getBytes(), objectName);
            if (Objects.isNull(resultURL))
                throw new CommonUtilsException(CommonUtilsException.SRC_UPLOAD_FAIL);
            // 通过上下文获取当前用户
            SysUserPo currentUser = BaseContextHolder.getContext().getBaseCurrentUser();
            // 修改数据库 -> 将objectName设置为新的avtar
            sysUserMapper.update(new LambdaUpdateWrapper<>(SysUserPo.class)
                    .set(SysUserPo::getAvatar, objectName)
                    .eq(SysUserPo::getId, currentUser.getId()));
            currentUser.setAvatar(objectName);
            // 修改联系人和会话信息
            modifyContactAndSessionInfo(currentUser);
            // 修改联系人信息
            return resultURL;
        } catch (IOException e) {
            throw new CommonUtilsException(CommonUtilsException.SRC_UPLOAD_FAIL);
        }
    }

    @Override
    @Transactional
    public void modifyPassword(SysUserModifyPwdDto sysUserModifyPwdDto) throws SysUserException {
        // 通过上下文获取当前用户
        SysUserPo currentUser = BaseContextHolder.getContext().getBaseCurrentUser();
        SysUserPo sysUserPo = sysUserMapper.selectOne(new LambdaQueryWrapper<>(SysUserPo.class).eq(SysUserPo::getId, currentUser.getId()));
        // 验证当前用户旧密码是否正确
        String md5_oldPwd = StringUtils.encodeByMd5(sysUserModifyPwdDto.getOldPwd(), userConfiguration.getPwdSalt());
        if (!Objects.equals(md5_oldPwd, sysUserPo.getPassword()))
            throw new SysUserException(SysUserException.PASSWORD_NOT_RIGHT);
        // 修改密码为新密码
        String md5_newPwd = StringUtils.encodeByMd5(sysUserModifyPwdDto.getNewPwd(), userConfiguration.getPwdSalt());
        sysUserMapper.update(new LambdaUpdateWrapper<>(SysUserPo.class).set(SysUserPo::getPassword, md5_newPwd).eq(SysUserPo::getId, currentUser.getId()));
    }

    @Override
    @Transactional
    public void modifyBaseInfo(SysUserModifyBaseInfoDto sysUserModifyBaseInfoDto) {
        // 通过上下文获取当前用户
        SysUserPo currentUser = BaseContextHolder.getContext().getBaseCurrentUser();
        // 修改用户信息
        SysUserPo modifyUserPo = BeanUtil.copyProperties(sysUserModifyBaseInfoDto, SysUserPo.class);
        modifyUserPo.setId(currentUser.getId());
        saveOrUpdate(modifyUserPo);
        // 修改联系人和会话信息
        modifyContactAndSessionInfo(modifyUserPo);
    }

    @Override
    public SysUserVo queryByToken() {
        // 通过上下文获取当前用户
        return userPoToVo(BaseContextHolder.getContext().getBaseCurrentUser());
    }

    @Override
    @Transactional
    public void rebindingRole(SysUserRebindingRoleDto sysUserRebindingRoleDto) throws SysUserException, SysRoleException {
        // 如果修改后的角色为超级管理员则不允许修改
        if (sysUserRebindingRoleDto.getRoleId().equals(CoreSysRole.SUPER_ADMIN.getId()))
            throw new SysRoleException(SysRoleException.ROLE_COULD_NOT_ACT);
        // 检查当前用户是否存在
        SysUserPo sysUserPo = userNotExistsThrow(sysUserRebindingRoleDto.getUserId());
        // 如果被修改的用户的角色是超级管理员，则不允许修改
        if (sysUserPo.getRoleId().equals(CoreSysRole.SUPER_ADMIN.getId()))
            throw new SysRoleException(SysRoleException.ROLE_COULD_NOT_ACT);
        // 检查角色是否存在
        roleNotExistsThrow(sysUserRebindingRoleDto.getRoleId());
        // 替换角色
        sysRoleUserMapper.update(new LambdaUpdateWrapper<>(SysRoleUserPo.class).eq(SysRoleUserPo::getUserId, sysUserRebindingRoleDto.getUserId())
                .set(SysRoleUserPo::getRoleId, sysUserRebindingRoleDto.getRoleId()));
        // 修改redis关系
        redisComponent.setRU_Relation(sysUserRebindingRoleDto.getUserId(), sysUserRebindingRoleDto.getRoleId());
    }

    @Override
    @Transactional
    public void modifyStatus(SysUserModifyStatusDto sysUserModifyStatusDto) throws AuthException, SysUserException, SysRoleException {
        // 当前用户是超级管理员则不允许修改
        Integer ruRoleId = redisComponent.getRU_RoleId(sysUserModifyStatusDto.getUserId());
        if (Objects.isNull(ruRoleId))
            throw new SysUserException(SysUserException.USER_NOT_EXISTS);
        if (ruRoleId.equals(CoreSysRole.SUPER_ADMIN.getId()))
            throw new SysRoleException(SysRoleException.ROLE_COULD_NOT_ACT);
        SysUserStatusEnum newStatus = SysUserStatusEnum.getByCode(sysUserModifyStatusDto.getStatus());
        if (Objects.isNull(newStatus))
            throw new SysUserException(SysUserException.USER_STATUS_ERROR);
        int update = sysUserMapper.update(new LambdaUpdateWrapper<>(SysUserPo.class)
                .set(SysUserPo::getStatus, newStatus.getCode())
                .eq(SysUserPo::getId, sysUserModifyStatusDto.getUserId()));
        if (update == 0)
            throw new SysUserException(SysUserException.USER_NOT_EXISTS);
    }

    @Override
    public PageBean<SysUserPo, SysUserVo> queryPage(Integer currentPage, Integer pageSize, String nickName, String phone, Integer status, Integer roleId) {
        MPJLambdaWrapper<SysUserPo> wrapper = new MPJLambdaWrapper<SysUserPo>()
                .leftJoin(SysRoleUserPo.class, SysRoleUserPo::getUserId, SysUserPo::getId)
                .selectAll(SysUserPo.class)
                .selectAs(SysRoleUserPo::getRoleId, SysUserPo::getRoleId)
                .eq(roleId != 0, SysRoleUserPo::getRoleId, roleId)
                .eq(status != 0, SysUserPo::getStatus, status)
                .like(!phone.isEmpty(), SysUserPo::getPhone, phone)
                .like(!nickName.isEmpty(), SysUserPo::getNickname, nickName)
                .orderByAsc(SysUserPo::getId);
        Page<SysUserPo> page = new Page<>(currentPage, pageSize);
        this.page(page, wrapper);
        ArrayList<SysUserVo> sysUserVos = new ArrayList<>();
        for (SysUserPo sysUserPo : page.getRecords()) {
            SysUserAdminVo sysUserAdminVo = BeanUtil.copyProperties(userPoToVo(sysUserPo), SysUserAdminVo.class);
            sysUserAdminVo.setPhone(sysUserPo.getPhone());
            sysUserAdminVo.setRoleId(sysUserPo.getRoleId());
            sysUserVos.add(sysUserAdminVo);
        }
        return new PageBean<>(page, sysUserVos);
    }

    private SysUserPo userNotExistsThrow(Integer uid) throws SysUserException {
        MPJLambdaWrapper<SysUserPo> wrapper = new MPJLambdaWrapper<SysUserPo>()
                .selectAll(SysUserPo.class)
                .selectAs(SysRoleUserPo::getRoleId, SysUserPo::getRoleId)
                .leftJoin(SysRoleUserPo.class, SysRoleUserPo::getUserId, SysUserPo::getId)
                .eq(SysUserPo::getId, uid);
        SysUserPo sysUserPo = getOne(wrapper);
        if (Objects.isNull(sysUserPo))
            throw new SysUserException(SysUserException.USER_NOT_EXISTS);
        return sysUserPo;
    }

    private SysRolePo roleNotExistsThrow(Integer roleId) throws SysRoleException {
        SysRolePo sysRolePo = sysRoleMapper.selectOne(new LambdaQueryWrapper<>(SysRolePo.class).eq(SysRolePo::getId, roleId));
        if (Objects.isNull(sysRolePo))
            throw new SysRoleException(SysRoleException.ROLE_NOT_EXISTS);
        return sysRolePo;
    }

    private SysUserVo userPoToVo(SysUserPo sysUserPo) {
        // 封装用户信息
        SysUserVo sysUserVo = BeanUtil.copyProperties(sysUserPo, SysUserVo.class);
        // 格式化时间
        sysUserVo.setFormatCreateTime(StringUtils.formatDateTime(sysUserPo.getCreateTime()));
        if (Objects.nonNull(sysUserPo.getLastLoginTime()))
            sysUserVo.setFormatLastLoginTime(StringUtils.formatDateTime(sysUserPo.getLastLoginTime()));
        // 获取头像地址
        sysUserVo.setAvatarUrl(aliyunOssUtils.generateUrl(sysUserPo.getAvatar()));
        return sysUserVo;
    }

    private void modifyContactAndSessionInfo(SysUserPo sysUserPo) {
        // 修改和该联系人有关的会话联系人头像
        List<Integer> contactIds = userContactMapper.selectList(new LambdaQueryWrapper<>(UserContactPo.class)
                        .eq(UserContactPo::getContactType, UserContactTypeEnum.USER.getCode())
                        .eq(UserContactPo::getContactId, sysUserPo.getId()))
                .stream().map(UserContactPo::getUserId).toList();
        if (!contactIds.isEmpty()) {
            chatSessionUserMapper.update(new LambdaUpdateWrapper<>(ChatSessionUserPo.class)
                    .in(ChatSessionUserPo::getContactId, contactIds)
                    .set(ChatSessionUserPo::getContactAvatar, sysUserPo.getAvatar())
                    .set(ChatSessionUserPo::getContactName, sysUserPo.getNickname()));
        }
    }

    private String generateToken(Integer uid) {
        // 生成token将用户id和数据token建立关系
        String partOne = StringUtils.encodeByMd5(uid.toString(), StringUtils.randomStr(32));
        String partTwo = StringUtils.randomStr(userConfiguration.getTokenLength());
        String token = partOne + partTwo;
        redisComponent.setToken(token, uid);
        return token;
    }

    private void reFleshLastLoginTime(Integer uid) {
        update(new LambdaUpdateWrapper<>(SysUserPo.class)
                .eq(SysUserPo::getId, uid)
                .set(SysUserPo::getLastLoginTime, LocalDateTime.now()));
    }

}
